package com.xbenben.demoroot.demo;

import com.xbenben.demoroot.bean.Dish;
import com.xbenben.demoroot.bean.UserLog;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author xbenbenx
 * Date:2022/8/15 22:36
 **/
@Slf4j
public class SteamDemo {

    public static List<Dish> menu;


    static {
        System.out.println("-----初始化数据--------");
        menu = Arrays.asList(
                new Dish("pork", false, 800, Dish.Type.MEAT),
                new Dish("pork", false, 800, Dish.Type.MEAT),
                new Dish("chicken", false, 400, Dish.Type.MEAT),
                new Dish("french fries", true, 530, Dish.Type.OTHER),
                new Dish("rice", true, 350, Dish.Type.OTHER),
                new Dish("season fruit", true, 120, Dish.Type.OTHER),
                new Dish("pizza", true, 550, Dish.Type.OTHER),
                new Dish("prawns", false, 300, Dish.Type.FISH),
                new Dish("salmon", false, 450, Dish.Type.FISH));
        menu.forEach(System.out::println);
        System.out.println("--------------------");
    }


    /**
     * 排序+过滤+指定字段获取 xbenben
     * 过滤 低热量(热量<400) 按照热量排序
     */
    @Test
    public void steamDemo_1() {

        List<Integer> collect = menu.stream()
                .filter((Dish d) -> d.getCalories() < 400)
                .sorted(Comparator.comparing(Dish::getCalories))
                .map(Dish::getCalories)
                .collect(Collectors.toList());
        collect.forEach(System.out::println);

        // 为了利用多核架构并行执行这段代码，你只需要把stream()换成parallelStream()：
        List<Integer> lowCaloricDishesName =
                menu.parallelStream()
                        .filter(d -> d.getCalories() < 400)
                        .sorted(Comparator.comparing(Dish::getCalories))
                        .map(Dish::getCalories)
                        .collect(Collectors.toList());

        lowCaloricDishesName.forEach(System.out::println);
    }


    /**
     * 分组 xbenben
     */
    @Test
    public void steamDemo_2() {

        // 按照类型 进行分组
        Map<Dish.Type, List<Dish>> collect = menu.stream().collect(Collectors.groupingBy(Dish::getType));
        //输出
        collect.entrySet().forEach(System.out::println);
    }


    /**
     * limit 截断  xbenben
     * skip 跳过
     * skip  和 limit 互补
     */
    @Test
    public void steamDemo_4() {
        List<String> title = Arrays.asList("Java8", "In", "Action");
        List<String> collectLimit = title.stream().limit(2).collect(Collectors.toList());
        List<String> collectSkip = title.stream().skip(2).collect(Collectors.toList());

        collectLimit.forEach(System.out::println);
        System.out.println("--------");
        collectSkip.forEach(System.out::println);

    }

    /**
     * 去重 distinct  xbenben
     */
    @Test
    public void steamDemo_5() {
        List<String> title = Arrays.asList("Java8", "Java8", "In", "Action");
        List<String> collect = title.stream().distinct().collect(Collectors.toList());
        collect.forEach(System.out::println);
        System.out.println("------");
        //筛选重复长度的单词
        title.stream().map(String::length).distinct().forEach(System.out::println);
        //输出 长度
        System.out.println("------");
        title.stream().map(String::length).forEach(System.out::println);
    }


    /**
     * 去重 distinct  xbenben
     */
    @Test
    public void steamDemo_7() {
        List<String> words = Arrays.asList("Java 8", "Java 8", "Lambdas", "In", "Action");
        //筛选重复长度的单词
        List<String> collect = words.stream()
                .map(word -> word.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());

        collect.forEach(System.out::println);

        //map  demo
        // (1) 给定一个数字列表，如何返回一个由每个数的平方构成的列表呢？例如，给定[1, 2, 3, 4,
        //          5]，应该返回[1, 4, 9, 16, 25]。
        //  答案：你可以利用map方法的Lambda，接受一个数字，并返回该数字平方的Lambda来解
        //  决这个问题。
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> squares =
                numbers.stream()
                        .map(n -> n * n)
                        .collect(Collectors.toList());
        squares.forEach(System.out::println);

        //(2) 给定两个数字列表，如何返回所有的数对呢？例如，给定列表[1, 2, 3]和列表[3, 4]，应
        // 该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]。为简单起见，你可以用有两个元素的数组来代
        // 表数对。
        // 答案：你可以使用两个map来迭代这两个列表，并生成数对。但这样会返回一个Stream-
        //         <Stream<Integer[]>>。你需要让生成的流扁平化，以得到一个Stream<Integer[]>。这
        // 正是flatMap所做的：
        List<Integer> numbers1 = Arrays.asList(1, 2, 3);
        List<Integer> numbers2 = Arrays.asList(3, 4);
        List<int[]> pairs =
                numbers1.stream()
                        .flatMap(i -> numbers2.stream()
                                .map(j -> new int[]{i, j})
                        )
                        .collect(Collectors.toList());
        pairs.forEach(res -> System.out.println(Arrays.toString(res)));

        //(3) 如何扩展前一个例子，只返回总和能被3整除的数对呢？例如(2, 4)和(3, 3)是可以的。
        // 答案：你在前面看到了，filter可以配合谓词使用来筛选流中的元素。因为在flatMap
        // 操作后，你有了一个代表数对的int[]流，所以你只需要一个谓词来检查总和是否能被3整除
        // 就可以了：
        List<int[]> pairsExcept =
                numbers1.stream()
                        .flatMap(i ->
                                numbers2.stream()
                                        .filter(j -> (i + j) % 3 == 0)
                                        .map(j -> new int[]{i, j})
                        )
                        .collect(Collectors.toList());
        pairsExcept.forEach(result -> System.out.println(Arrays.toString(result)));
        //其结果是[(2, 4), (3, 3)]。
    }


    /**
     * 查找和匹配  xbenben
     * 某些元素是否匹配一个给定的属性。Stream
     * API通过allMatch、anyMatch、noneMatch、findFirst和findAny方法提供了这样的工具。
     * anyMatch方法返回一个boolean，因此是一个终端操作。--匹配当前statem是否包含一个指定条件   xbenben
     */
    @Test
    public void steamDemoFind_1() {
        List<String> title = Arrays.asList("Java8", "Java8", "In", "Action");

        boolean b = title.stream().anyMatch("Java8"::equals);
        if (b) {
            System.out.println("存在");
        } else {
            System.out.println("不存在");
        }
        // anyMatch方法返回一个boolean，因此是一个终端操作。
    }


    /**
     * xbenben
     * allMatch 方法返回一个boolean 。--匹配当前statem是否 全部符合 指定条件   xbenben
     */
    @Test
    public void steamDemoFind_2() {
        List<String> title = Arrays.asList("Java8", "Java8", "In", "Action");
        boolean b = title.stream().allMatch("Java8"::equals);
        if (b) {
            System.out.println("存在");
        } else {
            System.out.println("不存在");
        }
        // anyMatch方法返回一个boolean，因此是一个终端操作。
    }

    /**
     *
     * noneMatch  xbenben
     * 和allMatch相对的是noneMatch。它可以确保流中没有任何元素与给定的谓词匹配。
     * noneMatch 方法返回一个boolean 。--匹配当前statem是否 全部不符合 指定条件
     */
    @Test
    public void steamDemoFind_3() {
        List<String> title = Arrays.asList("Java8", "Java8", "In", "Action");
        boolean b = title.stream().noneMatch("Java8"::equals);
        if (b) {
            System.out.println("存在");
        } else {
            System.out.println("不存在");
        }
        // anyMatch方法返回一个boolean，因此是一个终端操作。
        log.info("");
    }

    @Test
    public   void  steamDemoFind_4 (){

        ArrayList<String> words = new ArrayList<>();

        words.add("World");
        words.add("Hello");
        // words.stream().reduce()
        Optional<String> min = words.stream()
                .min((o1, o2) -> o2.compareTo(o1));
        System.out.println(min.get());


        // String

    }





}
